#include "../include/keyboard.h"
#include "../include/defs.h"
#include "../include/kc.h"

#define MAXLINEA    160

extern unsigned char *keyboardBuffer;
extern unsigned char _getcharNB(void);
extern unsigned char _getChar (void);

extern int pidActual;

unsigned char ascii_table[CLAVIER_NRO][KEYS_NRO] = {
    {
     ESC, NA, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
     '\b',

     '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
     NA,

     'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', LSHIFT,
     '\\', 'z', 'x',

     'c', 'v', 'b', 'n', 'm', ',', '.', '/', RSHIFT, '*', NA, ' ', CAPSLOCK,

     F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, NUMLOCK, NA, NA, UPARROW, NA,
     '-', LEFTARROW,

     NA, RIGHTARROW, '+', NA, DOWNARROW, NA, '0', NA, NA, NA, NA, F11, F12},
    {
     ESC, NA, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',
     '\b',

     '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
     NA,

     'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '|', LSHIFT, '\\',
     'Z', 'X',

     'C', 'V', 'B', 'N', 'M', '<', '>', '?', RSHIFT, '*', NA, ' ', CAPSLOCK,

     F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, NUMLOCK, NA, NA, UPARROW, NA,
     '-', LEFTARROW,

     NA, RIGHTARROW, '+', NA, DOWNARROW, NA, '0', NA, NA, NA, NA, F11, F12},
    {
     ESC, NA, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
     '\b',

     '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n',
     NA,

     'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', LSHIFT,
     '\\', 'Z', 'X',

     'C', 'V', 'B', 'N', 'M', ',', '.', '/', RSHIFT, '*', NA, ' ', CAPSLOCK,

     F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, NUMLOCK, NA, NA, UPARROW, NA,
     '-', LEFTARROW,

     NA, RIGHTARROW, '+', NA, DOWNARROW, NA, '0', NA, NA, NA, NA, F11, F12},
    {
     ESC, NA, '!', '@', '#', '$', '%', '{', '}', '*', '(', ')', '_', '+',
     '\b',

     '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '^', '&', '\n',
     NA,

     'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"', '|', LSHIFT, '\\',
     'z', 'x',

     'c', 'v', 'b', 'n', 'm', '<', '>', '?', RSHIFT, '*', NA, ' ', CAPSLOCK,

     F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, NUMLOCK, NA, NA, UPARROW, NA,
     '-', LEFTARROW,

     NA, RIGHTARROW, '+', NA, DOWNARROW, NA, '0', NA, NA, NA, NA, F11, F12}
};



/* Variables globales */
int shift = 0;
int capsLock = 0;
extern unsigned char *readBuffer;
extern unsigned char *writeBuffer;
extern int terminalActual;

char
getAscii (int scanCode) {
    /* Dado que el makecode de UPARROW y DOWNARROW es igual al ASCII de 'P' y 'H'
     *  vamos a tener que diferenciar entre ellos*/
    if (scanCode == UPARROW) {
        return UPARROW_EXTENDED;

    }
    else {
        if (scanCode == DOWNARROW)
            return DOWNARROW_EXTENDED;
    }

    setShift (scanCode);
    setCapsLock (scanCode);


    if (!shift && !capsLock)
        return ascii_table[0][scanCode];

    if (shift && !capsLock)
        return ascii_table[1][scanCode];

    if (!shift && capsLock)
        return ascii_table[2][scanCode];

    if (shift && capsLock)
        return ascii_table[3][scanCode];
}


void
addKeyToBuffer (unsigned char ascii) {
    if (writeBuffer - keyboardBuffer == MAXLINEA)
        writeBuffer = keyboardBuffer;

    *writeBuffer = ascii;
    writeBuffer++;
}

unsigned char
getcharNB (void) {
    PROCESO* proceso;
    proceso=GetProcessByPid (pidActual);
    if(terminalActual!=proceso->terminal || proceso->background )
    {
        asm volatile ("hlt");
        return -1;
    }
    else
    {
        if (readBuffer == writeBuffer)
        {
            asm volatile ("hlt");
            return -1;
        }
        else
            return *readBuffer++;
    }
}


unsigned char
GetChar (void) {
    PROCESO* proceso;
    proceso=GetProcessByPid(pidActual);
    
    while(readBuffer == writeBuffer) {
        if(proceso->bloqueado==0)
        {
            bloqueaProceso(pidActual, WAITING_INPUT);
            switch_manual();
        }
    }
    if (readBuffer - keyboardBuffer == MAXLINEA)
        readBuffer = keyboardBuffer;
    return *readBuffer++;
}


int
isFmake (int code) {

    unsigned char ascii = getAscii (code);


    /* Cheque si el code es makecode de algun F */

    if (code >= 0x3B && code <= 0x44 || code == 0x57 || code == 0x58)
        return 1;

    return 0;

}


int
canBeShowed (int code) {
    unsigned char ascii = getAscii (code);

    /* Dado que la tecla enter ejecuta una accion y su codigo ascii es tenido en
     * cuenta, no se agrega al de exclusion. */

    if (ascii >= F1 && ascii <= F10)
        return 0;

    if (ascii == F11 || ascii == F12)
        return 0;

    if (ascii != NA && code < 128 && code != LSHIFT && code != RSHIFT
        && code != LEFTARROW && code != RIGHTARROW && code != CAPSLOCK
        && code != NUMLOCK)
        return 1;

    return 0;
}

void
setShift (int scanCode) {
    int breakCode = scanCode & 0xFF7F;

    if (scanCode == LSHIFT || scanCode == RSHIFT)
        shift = 1;
    else {
        /* Hacemos un AND para ver si es un break. */
        if (breakCode == LSHIFT || breakCode == RSHIFT)
            shift = 0;
    }
}

void
setCapsLock (int scanCode) {
    static int count = 0;

    if (scanCode == CAPSLOCK) {
        if (++count == 2)
            capsLock = 1;
        else if (count > 3) {
            capsLock = 0;
            count = 0;
        }
    }
}
